﻿#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

//int main()
//{
//	const int a = 5;//此时a不能再改变值，是一个常变量
//	//在c++中，a变成常量
//	//a = 10;
//	int* p = &a;
//	*p = 0;
//	printf("%d", a);
//	return 0;
//}


//int main()
//{
//	int a = 10;
//	int b = 20;
//
//	int* const pa = &a;//修饰的是指针变量本身，不可以修改，但指针变量指向的内容可以修改
//	*pa = 100;
//
//	int const* pb = &b;//修饰的是指针变量指向的内容，不可以修改，但指针变量本身可以修改
//	pb = &a;
//
//	printf("%d\n", a);
//	printf("%d", *pb);
//
//	return 0;
//}

//指针的运算

//指+-整数
//int main()
//{
//	int arr[] = { 0,1,2,3,4,5,6,7,8,9 };
//	int* p = arr;//数组名等于数组首个元素的地址，arr=&arr[0]
//	int sz = sizeof(arr) / sizeof(arr[0]);
//	int i = 0;
//	for (i = 0; i < sz; i++)
//	{
//		printf("%d ", *(p + i));
//	}
//	return 0;
//}

//指针-指针
//指针+指针没有意义，所以没有这个算法
//指针+整数=指针，所以指针-指针还是整数

//int my_strlen(char* p)//用来接收地址
//{
//	int count = 0;
//	while (*p != '\0')
//	{
//		count++;
//		p++;
//	}
//	return count;
//}

//用地址相减来计算字符串的个数
//int my_strlen(char* p)//用来接收地址
//{
//	char* p1 = p;
//
//	while (*p != '\0')
//	{
//		p++;
//	}
//	return p-p1;
//}
//
//int main()
//{
//	char arr[] = "abcd";
//	int count = my_strlen(arr);
//	printf("%d", count);
//	return 0;
//}

//指针的关系运算
//int main()
//{
//	int arr[] = { 0,1,2,3,4,5,6,7,8,9 };
//	int sz = sizeof(arr) / sizeof(arr[0]);
//	int* p = arr;
//	while (p < arr + sz)//指针大小的比较
//	{
//		printf("%d ", *p);
//		p++;
//	}
//	return 0;
//}

//野指针

//指针未初始化
//指针越界访问
//见课件

//指针指向的空间释放

//int* test()
//{
//	int n = 100;
//	return &n;
//}
//
//int main()
//{
//	int* p = test();
//	printf("%d", *p);
//	return 0;
//}

//为了防止指针越界，可以给指针初始化
//也可以设置空指针NULL

//int main()
//{
//	int* p = NULL;//意思是这个指针为空指针，不能再动这个指针了
//	return 0;
//}

//assert断言
//assert（你想要满足的条件）
//如果你想要取消使用assert，定义NOEBUG,release版本自动不使用assert

//int main()
//{
//	//我们进行操作的指针不能是空指针
//	int a = 10;
//	int* p = &a;
//	assert(p != NULL);//p不能是空指针，否则会报错
//	return 0;
//}

//传值调用和传址调用

//只能用指针的情况，交换两个整数的值

//void swap(int x, int y)//这里是无法交换的，因为形参地址和实参地址是不一样的，改变的是形参的值，不是实参的值
//{
//	int temp = x;
//	 x = y;
//	 y = temp;
//}

//void swap(int* pa, int* pb)//接收a和b的地址，直接和a，b产生联系
//{
//	int temp = 0;
//	temp = *pa;
//	*pa = *pb;
//	*pb = temp;
//}
//
//int main()
//{
//	int a = 10;
//	int b = 20;
//	printf("交换前a和b的值%d,%d\n", a, b);
//	swap(&a, &b);
//	printf("交换后a和b的值%d,%d", a, b);
//	return 0;
//}

//传址调⽤，可以让函数和主调函数之间建⽴真正的联系，在函数内部可以修改主调函数中的变量；所
//以未来函数中只是需要主调函数中的变量值来实现计算，就可以采⽤传值调⽤。如果函数内部要修改
//主调函数中的变量的值，就需要传址调⽤。


//数组名就是数组首个元素的地址

//特例，sizeof（arr）这里arr表示的整个数组的大小，计算整个数组的大小单位是字节

//int main()
//{
//	int arr[10] = { 0 };
//	printf("%p\n", &arr[0]);//和arr地址完全一致
//	printf("%p\n", &arr[0]+1);//这里是加了四个字节
//
//	printf("%p\n", arr);
//	printf("%p\n", arr+1);
//
//	printf("%p\n", &arr);
//	printf("%p\n", &arr+1);//这里加了四十个字节，说明这里是整个数组的地址，这里一个数组的地址是40节
//}


//使用指针访问数组

//int main()
//{
//	int arr[10] = { 0 };
//	int sz = sizeof(arr) / sizeof(arr[0]);
//	int i = 0;
//	int* p = arr;
//	for (i = 0; i < sz; i++)
//	{
//		scanf("%d", p + i);
//	}
//	for (i = 0; i < sz; i++)
//	{
//		printf("%d ", *(p + i));
//	}
//}

//创建函数来打印

//void print(int arr[],int sz)
//{
//	int* p = arr;
//	int i = 0;
//	for (i = 0; i < sz; i++)
//	{
//		scanf("%d", p + i);
//	}
//	for (i = 0; i < sz; i++)
//	{
//		printf("%d ", *(p + i));
//		//因为这p就是arr的地址，所以*（p+i）=*(arr+i)
//		//同时我们也可以写成arr[i],那么也就可以写成p[i]
//		//这里扩展一下，*（p+i）=*（i+p）、*(arr+i)=*(i+arr)，那么也就可以写成i[p]、i[arr]
//		//不过不建议那么使用，不好理解
//	}
//}
//
//int main()
//{
//	int arr[10] = { 0 };
//	int sz = sizeof(arr) / sizeof(arr[0]);
//	//这里的sizeof不能写在函数里面，因为arr传过去的数组首个元素的地址
//	//实际上应该是print（int* arr）,但可以省略，所以这时arr就是首个元素的地址
//	//只有四个字节，则sz算出来的结果是4/4为1
//	print(arr, sz);
//}

//冒泡排序

//void paixu(int arr[], int sz)
//{
//	int i = 0;
//	int j = 0;
//	for (i = 0; i < sz - 1; i++)
//	{//排序次数
//		int flag = 0;//当进行一次排序一个没动时，flag的值不变
//		for (j = 0; j < sz - 1 - i; j++)
//		{
//			if (arr[j] > arr[j + 1])
//			{
//				int temp = arr[j];
//				arr[j] = arr[j + 1];
//				arr[j + 1] = temp;
//				flag = 0;
//			}
//		}
//		if (flag == 1)//当flag是1的时候，说明排序已经完成，跳出循环
//			break;
//	}
//}
//
//void print(int arr[], int sz)
//{//打印数组
//	int i = 0;
//	for (i = 0; i < sz; i++)
//	{
//		printf("%d ", arr[i]);
//	}
//}
//
//int main()
//{
//	int arr[] = { 9,8,7,6,5,4,3,2,1 };
//	int sz = sizeof(arr) / sizeof(arr[0]);
//	paixu(arr, sz);
//	print(arr, sz);
//	return 0;
//}

//二级指针

//int main()
//{
//	int a = 10;
//	int* p = &a;//这是一级指针，p是a的地址
//	int** pp = &p;//这是二级指针，也就是说pp是指针变量p的地址
//	//打印出来对比
//	printf("%p\n", pp);
//	printf("%p\n", &p);
//	
//
//	printf("%p\n", p);
//	printf("%p\n", &a);
//	printf("%p\n", *pp);
//	printf("%d\n", **pp);
//}

//指针数组

//指针数组模拟打印二维数组

//int main()
//{
//	int arr0[] = { 1,2,3,4,5 };
//	int arr1[] = { 2,3,4,5,6 };
//	int arr2[] = { 3,4,5,6,7 };
//
//	int* arr[] = { arr0,arr1,arr2 };
//
//	int sz = sizeof(arr) / sizeof(arr[0]);
//
//	int i = 0;
//	int j = 0;
//	for (i = 0; i < sz; i++)
//	{
//		for (j = 0; j < 5; j++)
//		{
//			printf("%d ", arr[i][j]);
//			//这里arr并不是二维数组，我们可以把它拆解开来
//			//arr[i][j]---*(*(arr+i)+j)
//		}
//		printf("\n");
//	}
//}

//字符指针变量

//int main()
//{
//	/*char ch = 'w';
//	char* p = &ch;
//	printf("%c", *p);*/
//
//	char chr[] = "abcde";
//	char* p = "abcde";//这里是把字符串的首字母地址存放到指针中
//	char* pa = "abcde";
//	printf("%c\n", *p);
//	printf("%s\n", p);
//	printf("%p\n", p);
//	printf("%p\n", pa);//pa和p中存放的都是a的地址，所以二者的地址相同
//	printf("%p\n", &p);
//	printf("%p\n", &pa);//指针变量的地址就不相同了
//}

//数组指针

//int main()
//{
//	int a = 10;
//	int* p = &a;
//	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//	int (*parr)[10] = &arr;//parr是个指针变量，指向数组，类型int * [10]

//}


//二维数组传参的本质

//void print(int (*arr)[5], int x, int y)
////二维数组的首元素就是第一行，也就是第一行组成的一位数组，所以这里的指针变量用来接收一维数组的传参
//{
//	int i = 0;
//	int j = 0;
//	for (i = 0; i < x; i++)
//	{
//		for (j = 0; j < y; j++)
//		{
//			printf("%d", *(*(arr + i) + j));//这里实际上就是arr[i][j]
//		}
//		printf("\n");
//	}
//}
//
//
//int main()
//{
//	int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
//	print(arr, 3, 5);//不管是一维数组还是二维数组，数组名都是首元素的地址，只有两个特例，sizeof（arr）
//	//和&arr，这两个是整个数组的地址，但一维数组和二维数组的首元素有所不同
//	return 0;
//}



//指针数组的运用---转移表

//int add(int x, int y)
//{
//	return x + y;
//}
//
//int sub(int x, int y)
//{
//	return x - y;
//}
//
//int mul(int x, int y)
//{
//	return x * y;
//}
//
//int div(int x, int y)
//{
//	return x / y;
//}
//
//void menu()
//{
//	printf("********************************\n");
//	printf("******    1.add   2.sub    *****\n");
//	printf("******    3.mul   4.div    *****\n");
//	printf("******        0.exit       *****\n");
//	printf("********************************\n");
//}
//
//int main()
//{
//	int (*parr[5])(int, int) = { 0,add,sub,mul,div };
//	menu();
//	int input = 0;
//	printf("请选择你需要的算法：\n");
//	scanf("%d", &input);
//	int x = 0;
//	int y = 0;
//	printf("请输入你的操作数");
//	scanf("%d %d", &x, &y);
//	int r = 0;
//	r = parr[input](x,y);
//	printf("%d", r);
//
//	return 0;
//}


//回调函数

//void menu()
//{
//	printf("********************************\n");
//	printf("******    1.add   2.sub    *****\n");
//	printf("******    3.mul   4.div    *****\n");
//	printf("******        0.exit       *****\n");
//	printf("********************************\n");
//}
//
//int add(int x, int y)
//{
//	return x + y;
//}
//
//int sub(int x, int y)
//{
//	return x - y;
//}
//
//int mul(int x, int y)
//{
//	return x * y;
//}
//
//int div(int x, int y)
//{
//	return x / y;
//}
//
//void hanshu(int (*p)(int, int))
//{
//	int x = 0;
//	int y = 0;
//	printf("请输入你的操作数：");
//	scanf("%d %d", &x, &y);
//	int r = p(x, y);
//	printf("%d", r);
//}
//
//int main()
//{
//	menu();
//	int input = 0;
//	printf("请输入你需要的算法：");
//	scanf("%d", &input);
//	switch (input)
//	{
//	case 1:
//		hanshu(add);//此时add,sub,mul,div就是回调函数，以指针的形式在一个函数中被引用
//		break;
//	case 2:
//		hanshu(sub);
//		break;
//	case 3:
//		hanshu(mul);
//		break;
//	case 4:
//		hanshu(div);
//		break;
//	case 0:
//		printf("结束计算");
//		break;
//	default:
//		printf("重新输入，你输错了");
//	}
//	return 0;
//}

//qsort函数的使用（4.27）


//#include<stdlib.h>是qsort库函数的头文件

//void print(int arr[],int sz)//打印函数
//{
//	int i = 0;
//	for (; i < sz; i++)
//	{
//		printf("%d", arr[i]);
//	}
//}
//
//int compare(const void* p1, const void* p2)
//{
//	return *(int*)p1 - *(int*)p2;//p1就是数组第一个元素，p2就是数组第二个元素
//	//p1比p2大就返回一个大于0的值，小就返回小于0的值，相同就返回0，大于0就互换位置
//	//所以*(int*)p2 - *(int*)p1就是降序排序，而原来的就是升序排序
//}
//
//int main()
//{
//	int arr[] = { 0,4,7,6,2,4,8,9,1,3,5 };
//	int sz = sizeof(arr) / sizeof(arr[0]);
//	qsort(arr, sz, sizeof(arr[0]), compare);//这里的指针变量指向一个定义比较大小方法的函数
//	print(arr, sz);
//
//	return 0;
//}

//qsort函数对结构体的排序

//struct stu
//{
//	char name[20];
//	int age;
//};
//
//int compare_name(void* p1, void* p2)
//{
//	return strcmp(((struct stu*)p1)->name, ((struct stu*)p2)->name);
//}
//
//int main()
//{
//	struct stu s[3] = { {"zhangsan",15},{"lisi",17},{"wangwu",18} };
//	int sz = sizeof(s) / sizeof(s[0]);
//	qsort(s, sz, sizeof(s[0]), compare_name);
//	//printf("%d\n", sizeof(s[0]));
//	//printf("%d", sizeof(s[1]));
//	//printf("%d", sizeof(struct stu));
//}

//qsort函数的模拟实现
//struct stu
//{
//	char name[20];
//	int age;
//};
//
//void Swap(char* x, char* y,int withy)
//{
//	int i = 0;
//	for (i = 0; i < withy; i++)
//	{
//		char temp = *x;
//		*x = *y;
//		*y = temp;
//		y++;
//		x++;
//	}
//}
//
//int compare1(const void* p1, const void* p2)
//{
//	return *(int*)p1 - *(int*)p2;
//}
//
//int compare2(const void* p3, const void* p4)
//{
//	return strcmp(((struct stu*)p3)->name, ((struct stu*)p4)->name);
//}
//
//int compare3(const void* p3, const void* p4)
//{
//	return ((struct stu*)p3)->age- ((struct stu*)p4)->age;
//}
//
//void my_qsort(void* base, size_t sz, size_t withy, int (*p)(const void* p1,const void* p2))
//{
//	int i = 0;
//	int j = 0;
//	for (i = 0; i < sz - 1; i++)
//	{
//		for (j = 0; j < sz - 1 - i; j++)
//		{
//			if (p((char*)base + j * withy, (char*)base + (j + 1) * withy) > 0)
//			{
//				Swap((char*)base + j * withy, (char*)base + (j + 1) * withy, withy);
//			}
//		}
//	}
//}
//
//void print(int arr[], int sz)//打印函数
//{
//	int i = 0;
//	for (; i < sz; i++)
//	{
//		printf("%d ", arr[i]);
//	}
//}
//
//
//int main()
//{
//	int arr[] = { 0,4,7,6,2,8,9,1,3,5 };
//	struct stu s[3] = { {"zhangsan",15},{"lisi",17},{"wangwu",18} };
//	int sz = sizeof(arr) / sizeof(arr[0]);
//	int sz1 = sizeof(s) / sizeof(s[0]);
//	my_qsort(arr, sz, sizeof(arr[0]), compare1);//这里的指针变量指向一个定义比较大小方法的函数
//	my_qsort(s, sz1, sizeof(s[0]), compare2);
//	my_qsort(s, sz1, sizeof(s[0]), compare3);
//	print(arr, sz);
//
//	return 0;
//}


                                        //5.08
                                                                
//指针的题目举例

////题目一
//#include <stdio.h>
//int main()
//{
//    int a[5] = { 1, 2, 3, 4, 5 };
//    int* ptr = (int*)(&a + 1);
//    printf("%d,%d", *(a + 1), *(ptr - 1));//2，5
//    return 0;
//}
//
//// 题目二
//
//struct test
//{
//int Num;
//char* pcName;
//short sDate;
//char cha[2];
//short sBa[4];
//}*p = (struct Test*)0x100000;
//int main()
//{
//    printf("%p\n", p + 0x1);
//    printf("%p\n", (unsigned long)p + 0x1);
//    printf("%p\n", (unsigned int*)p + 0x1);
//    return 0;
//}
//
//
////题目三
//
//int Num;
//char* pcName;
//short sDate;
//char cha[2];
//short sBa[4];
//}*p = (struct Test*)0x100000;
//int main()
//{
//    printf("%p\n", p + 0x1);
//    printf("%p\n", (unsigned long)p + 0x1);
//    printf("%p\n", (unsigned int*)p + 0x1);
//    return 0;
//}
//
//
////题目四
//
//
//int Num;
//char* pcName;
//short sDate;
//char cha[2];
//short sBa[4];
//}*p = (struct Test*)0x100000;
//int main()
//{
//    printf("%p\n", p + 0x1);
//    printf("%p\n", (unsigned long)p + 0x1);
//    printf("%p\n", (unsigned int*)p + 0x1);
//    return 0;
//}
//
////题目五
//
//int Num;
//char* pcName;
//short sDate;
//char cha[2];
//short sBa[4];
//}*p = (struct Test*)0x100000;
//int main()
//{
//    printf("%p\n", p + 0x1);
//    printf("%p\n", (unsigned long)p + 0x1);
//    printf("%p\n", (unsigned int*)p + 0x1);
//    return 0;
//}
//
////题目六
//
//#include <stdio.h>
//int main()
//{
//    char* a[] = { "work","at","alibaba" };
//    char** pa = a;
//    pa++;
//    printf("%s\n", *pa);
//    return 0;
//}
//
////题目七
//
//
//#include <stdio.h>
//int main()
//{
//    char* c[] = { "ENTER","NEW","POINT","FIRST" };
//    char** cp[] = { c + 3,c + 2,c + 1,c };
//    char*** cpp = cp;
//    printf("%s\n", **++cpp);
//    printf("%s\n", *-- * ++cpp + 3);
//    printf("%s\n", *cpp[-2] + 3);
//    printf("%s\n", cpp[-1][-1] + 1);
//    return 0;
//}


                                             //5.08
//字符函数的使用

//字符串的大小写转换

//#include<ctype.h>
//
//int main()
//{
//    char s[] = "i am a student";
//    int i = 0;
//    while (s[i] != '\0')
//    {
//        if (isupper(s[i]))//isupper函数的作用就是如果s[i]为小写字母就为0，大写就不为0
//            //islower函数的作用则是小写字母为不为0，大写字母为0
//        {
//            s[i] = tolower(s[i]);//tolower函数的作用是将大写字母转化为小写字母
//            //toupper函数的作用则是将小写字母转化为大写字母
//        }
//        i++;
//    }
//    printf("%s", s);
//}

//strlen函数的模拟实现方法

//方法一

//size_t my_strlen(const char* s)
//{
//    int i = 0;
//    int count = 0;
//    while (s[i] != '\0')
//    {
//        count++;
//        i++;
//    }
//    return count;
//}
//
//
//
//int main()
//{
//    char s[] = "abcdef";
//    int r = my_strlen(s);
//    printf("%d", r);
//}


//方法二---递归

//size_t my_strlen(const char* s)
//{
//    if (*s == '\0')
//        return 0;
//    else
//        return 1 + my_strlen(s + 1);
//}
//
//int main()
//{
//    char s[] = "abcdef";
//    int r = my_strlen(s);
//    printf("%d", r);
//}

#include<string.h>

//strcpy函数的使用方法
//int main()
//{
//    char arr1[20] =  "hello bit" ;
//    char arr2[20] = { 0 };
//    strcpy(arr2, arr1);//将arr2拷贝到arr1里去，\0也拷贝进去
//    printf("%s", arr2);
//}

//strcat函数的使用方法 5.10
//int main()
//{
//    char arr1[20] = "hello ";
//    char arr2[] = "world";
//    char* p = strcat(arr1, arr2);//将arr拷贝到arr1里，不过是从arr1里的\0位置开始考
// 相当于将两个数列连接
//    printf("%s\n", arr1);
//    printf("%s\n", p);
//    printf("%s\n", strcat(arr1, arr2));
//
//    return 0;
//}




int main()
{
    int a = 10;
    int* p = &a;
    char* pa = &a;
    printf("%d ,%d", *p, *pa);
}